import { Matrix } from "../d2/math/Matrix";
import { Vec2 } from "../d2/math/Vec2";
import { Cls, IVec2 } from "../util/Defined";
import { IPoolObj, Pool } from "../util/Pool";
import { ECSCmp } from "./ECSCmp";
import { ECSCmpMgr } from "./ECSCmpMgr";
import { ECSPoolCmp } from "./ECSPoolCmp";
import { ECSScene } from "./ECSScene";

/**
 * [ECS]实体
 */
export class ECSEntity implements IPoolObj {
	/** 实体id */
	id: number;
	/** 实体标签 可以用来在实体管理器中快速筛选实体 */
	tag: any;
	/** 所在场景 */
	scene: ECSScene;
	/** 被标记移除 在下一帧帧循环开始将被移除 */
	removed: boolean;

	/** 是否不在场景 */
	get dead() {
		return !this.scene;
	}

	/**
	 * 从场景中移除自己
	 */
	removeSelf() {
		this.scene.removeEntity(this);
	}

	// ============ 变换 ============

	protected _rot: number;
	protected _dir = new Vec2();
	protected _dirChanged: boolean;
	protected _scale = new Vec2();
	protected _trans: Matrix;
	protected _transChanged: boolean;

	/** 在场景中的坐标 */
	readonly pos = new Vec2();

	/** 旋转值(弧度) */
	get rot() {
		return this._rot;
	}

	set rot(v: number) {
		this._rot = v;
		this._dirChanged = true;
		this._transChanged = true;
	}

	/** 朝向(请通过setDir或rot设置) */
	get dir(): Readonly<IVec2> {
		if (this._dirChanged) {
			this._dirChanged = false;
			this._dir.setPos(Math.cos(this._rot), Math.sin(this._rot));
		}
		return this._dir;
	}

	/** 缩放(请通过setScale设置) */
	get scale(): Readonly<IVec2> {
		return this._scale;
	}

	/** 设置朝向 */
	setDir(x: number, y: number) {
		Vec2.setPos(this.dir, x, y);
		this._rot = Math.atan2(y, x);
		this._transChanged = true;
	}

	/** 设置朝向 */
	setDirTo(dir: Readonly<IVec2>) {
		this.setDir(dir.x, dir.y);
	}

	/** 设置缩放 */
	setScale(x: number, y = x) {
		Vec2.setPos(this.scale, x, y);
		this._transChanged = true;
	}

	/** 旋转变换矩阵 */
	get trans() {
		if (this._transChanged) {
			this._transChanged = false;
			const mat: Matrix = this._trans || (this._trans = new Matrix());
			if (this._rot || this.scale.x !== 1 || this.scale.y !== 1) {
				mat.setTranslate(0, 0).setScaleRotation(this._rot, this.scale.x, this.scale.y);
			} else {
				mat.identity();
			}
		}
		return this._trans;
	}

	// ============ 组件 ============

	/** 组件管理器 */
	readonly cmpMgr = new ECSCmpMgr(this);

	/**
	 * 是否存在对应组件
	 * @param cmpType 组件类型
	 */
	hasCmp(cmpType: Cls<ECSCmp>) {
		return this.cmpMgr.has(cmpType);
	}

	/**
	 * 获取对应组件类型的第一个组件
	 * @param cmpType 组件类型
	 * @param checkAdd 只获取已执行了onAdd的组件
	 */
	getCmp<T extends ECSCmp>(cmpType: Cls<T>, checkAdd = false): T {
		return this.cmpMgr.get(cmpType, checkAdd);
	}

	/**
	 * 获取对应组件类型的所有组件
	 * @param cmpType 组件类型
	 * @param checkAdd 只获取已执行了onAdd的组件
	 */
	getCmps<T extends ECSCmp>(cmpType: Cls<T>, checkAdd = false): readonly T[] {
		return this.cmpMgr.getAll(cmpType, checkAdd);
	}

	/**
	 * 获取对应组件类型的第一个组件 如果没有则添加
	 * @param cmpType 组件类型
	 * @param checkAdd 只获取已执行了onAdd的组件
	 */
	getOrAddCmp<T extends ECSCmp>(cmpType: Cls<T>, checkAdd = false): T {
		return this.getCmp(cmpType, checkAdd) || this.addCmp(cmpType);
	}

	/**
	 * 获取对应组件类型的第一个组件 如果没有则添加
	 * @param cmpPool 组件对象池
	 * @param checkAdd 只获取已执行了onAdd的组件
	 */
	getOrAddCmpByPool<T extends ECSCmp>(cmpPool: Pool<T>, checkAdd = false): T {
		return this.getCmp(cmpPool.cls, checkAdd) || this.addCmpByPool(cmpPool);
	}

	/**
	 * 添加组件
	 * @param cmpType 组件类型
	 */
	addCmp<T extends ECSCmp>(cmpType: Cls<T>): T {
		return this.cmpMgr.add(new cmpType());
	}

	/**
	 * 添加组件(通过对象池)
	 * @param cmpPool 组件对象池
	 */
	addCmpByPool<T extends ECSPoolCmp>(cmpPool: Pool<T>): T {
		return this.cmpMgr.add(cmpPool.alloc());
	}

	/**
	 * 添加组件(通过对象池带参数)
	 * @param cmpPool 组件对象池
	 * @param args 参数
	 */
	addCmpByPoolArgs<T extends ECSPoolCmp>(cmpPool: Pool<T>, ...args: any[]): T {
		return this.cmpMgr.add(cmpPool.allocArgs(...args));
	}

	/**
	 * 移除组件
	 * @param cmp 组件
	 */
	removeCmp(cmp: ECSCmp) {
		return this.cmpMgr.remove(cmp);
	}

	/**
	 * 移除组件类型
	 * @param cmpType 组件类型
	 */
	removeCmpType(cmpType: Cls<ECSCmp>) {
		return this.cmpMgr.removeType(cmpType);
	}

	// ============ 生命周期 ============

	onAlloc(...args: any[]) {
		this.pos.resetPos();
		this._rot = 0;
		this._dirChanged = true;
		this._scale.resetPos();
		this._trans?.identity();
		this._transChanged = true;
		this.removed = false;
		this.tag = null;
	}

	onFree(): void {
		this.scene = null;
	}

	/**
	 * 当被添加到场景时触发
	 * @param id
	 * @param scene
	 */
	onAdd() {
		this.cmpMgr.updateAdd();
	}

	/**
	 * 当从场景中移除时触发
	 */
	onRemove() {
		this.cmpMgr.clear();
		this.scene = null;
	}
}
